package pay

import (
	"errors"
	"github.com/iGoogle-ink/gopay"
	"github.com/iGoogle-ink/gopay/wechat"
	"github.com/iGoogle-ink/gotil"
	"github.com/iGoogle-ink/gotil/xlog"
	"strconv"
	"time"
)

type WeChatPayConfig struct {
	Appid          string
	MchId          string
	ApiKey         string
	IsProd         bool
	CertFilePath   string
	KeyFilePath    string
	Pkcs12FilePath string
	NotifyUrl      string
	ReturnUrl      string
	WapUrl         string
}

func (a *WeChatPayConfig) GetNotifyUrl() string {
	return a.NotifyUrl
}

type WeChatPay struct {
	conf   *WeChatPayConfig
	client *wechat.Client
}

type WeChatPayUnified struct {
	bm        gopay.BodyMap
	wxRsp     *wechat.UnifiedOrderResponse
	timeStamp string
}

//H5签名
func (a *WeChatPayUnified) H5PaySign(appId, nonceStr, apiKey string) string {
	pac := "prepay_id=" + a.wxRsp.PrepayId
	return wechat.GetH5PaySign(appId, nonceStr, pac, wechat.SignType_MD5, a.timeStamp, apiKey)
}

//小程序签名
func (a *WeChatPayUnified) WeAppPaySign(appId, nonceStr, apiKey string) string {
	pac := "prepay_id=" + a.wxRsp.PrepayId
	return wechat.GetMiniPaySign(appId, nonceStr, pac, wechat.SignType_MD5, a.timeStamp, apiKey)
}
func NewWeChatPayUnified() *WeChatPayUnified {
	return &WeChatPayUnified{
		bm:        make(gopay.BodyMap),
		timeStamp: strconv.FormatInt(time.Now().Unix(), 10),
	}
}

//小程序下单
func (a *WeChatPay) WeAppUnifiedOrder(money int, openId string) (*OderInfo, error) {

	we := NewWeChatPayUnified()
	//初始化参数Map

	we.bm.Set("spbill_create_ip", "127.0.0.1")
	we.bm.Set("notify_url", a.conf.GetNotifyUrl())
	we.bm.Set("sign_type", wechat.SignType_MD5)

	we.bm.Set("trade_type", wechat.TradeType_JsApi)
	we.bm.Set("device_info", "小程序")
	we.bm.Set("nonce_str", gotil.GetRandomString(32))

	we.bm.Set("body", "产品支付")

	number := gotil.GetRandomString(32)
	xlog.Debug("out_trade_no:", number)
	we.bm.Set("out_trade_no", number)
	we.bm.Set("total_fee", money)
	we.bm.Set("openid", openId)

	//场景信息，非必填
	//sceneInfo := make(map[string]map[string]string)
	//h5Info := make(map[string]string)
	//h5Info["type"] = "Wap"
	//h5Info["wap_url"] = a.conf.WapUrl
	//h5Info["wap_name"] = "H5测试支付"
	//sceneInfo["h5_info"] = h5Info
	//we.bm.Set("scene_info", sceneInfo)

	wxRsp, err := a.client.UnifiedOrder(we.bm)
	if err != nil {
		xlog.Error(err)
		return nil, err
	}
	if wxRsp.ReturnCode == "FAIL" {
		return nil, errors.New("下单失败：" + wxRsp.ReturnMsg)
	}
	if wxRsp.ResultCode == "FAIL" {
		return nil, errors.New(wxRsp.ErrCode + ":" + wxRsp.ErrCodeDes)
	}
	we.wxRsp = wxRsp
	nonceStr := gotil.GetRandomString(32)

	return &OderInfo{
		TimeStamp:    we.timeStamp,
		NonceStr:     nonceStr,
		Package:      we.wxRsp.PrepayId,
		SignType:     wechat.SignType_MD5,
		AppId:        a.conf.Appid,
		PaySign:      we.WeAppPaySign(a.conf.Appid, nonceStr, a.conf.ApiKey),
		OutOrderId: number,
	}, nil
}

type OderInfo struct {
	TimeStamp    string `json:"time_stamp"`
	NonceStr     string `json:"nonce_str"`
	Package      string `json:"package"`
	SignType     string `json:"sign_type"`
	AppId        string `json:"app_id"`
	PaySign      string `json:"pay_sign"`
	OutOrderId string `json:"out_order_id"`
}

//H5下单
func (a *WeChatPay) H5UnifiedOrder() (string, error) {
	we := NewWeChatPayUnified()

	we.bm.Set("trade_type", wechat.TradeType_H5)
	we.bm.Set("device_info", "WEB")
	we.bm.Set("nonce_str", gotil.GetRandomString(32))

	we.bm.Set("body", "产品支付")

	number := gotil.GetRandomString(32)
	xlog.Debug("out_trade_no:", number)
	we.bm.Set("out_trade_no", number)
	we.bm.Set("total_fee", 1)

	sceneInfo := make(map[string]map[string]string)
	h5Info := make(map[string]string)
	h5Info["type"] = "Wap"
	h5Info["wap_url"] = a.conf.WapUrl
	h5Info["wap_name"] = "H5测试支付"
	sceneInfo["h5_info"] = h5Info
	we.bm.Set("scene_info", sceneInfo)

	wxRsp, err := a.client.UnifiedOrder(we.bm)
	if err != nil {
		xlog.Error(err)
		return "", err
	}

	if wxRsp.ReturnCode == "FAIL" {
		return "", errors.New("下单失败：" + wxRsp.ReturnMsg)
	}

	return wxRsp.MwebUrl, nil
}

func NewWeChatPay(c *WeChatPayConfig) *WeChatPay {

	//设置国家
	we := new(WeChatPay)
	we.conf = c
	we.client = wechat.NewClient(c.Appid, c.MchId, c.ApiKey, c.IsProd)
	we.client.SetCountry(wechat.China)

	if len(c.CertFilePath) == 0 || len(c.KeyFilePath) == 0 || len(c.Pkcs12FilePath) == 0 {
		return we
	}

	// 设置证书
	err := we.client.AddCertFilePath(c.CertFilePath, c.KeyFilePath, c.Pkcs12FilePath)
	if err != nil {
		panic(err)
	}

	return we
}
